1 /* 2 * Copyright 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.conscrypt; 18 19 import java.io.IOException; 20 import java.security.AlgorithmParametersSpi; 21 import java.security.spec.AlgorithmParameterSpec; 22 import java.security.spec.InvalidParameterSpecException; 23 import java.security.spec.MGF1ParameterSpec; 24 import java.security.spec.PSSParameterSpec; 25 26 /** 27 * AlgorithmParameters implementation for PSS. The only supported encoding format is ASN.1 28 * (with X.509 accepted as an alias), as specified in RFC 4055 section 3.1. 29 */ 30 @Internal 31 public class PSSParameters extends AlgorithmParametersSpi { 32 33 private PSSParameterSpec spec = PSSParameterSpec.DEFAULT; 34 PSSParameters()35 public PSSParameters() {} 36 37 @Override engineInit(AlgorithmParameterSpec algorithmParameterSpec)38 protected void engineInit(AlgorithmParameterSpec algorithmParameterSpec) 39 throws InvalidParameterSpecException { 40 if (algorithmParameterSpec instanceof PSSParameterSpec) { 41 this.spec = (PSSParameterSpec) algorithmParameterSpec; 42 } else { 43 throw new InvalidParameterSpecException("Only PSSParameterSpec is supported"); 44 } 45 } 46 47 @Override engineInit(byte[] bytes)48 protected void engineInit(byte[] bytes) throws IOException { 49 long readRef = 0; 50 long seqRef = 0; 51 try { 52 readRef = NativeCrypto.asn1_read_init(bytes); 53 seqRef = NativeCrypto.asn1_read_sequence(readRef); 54 int saltLength = 20; 55 String hash = OAEPParameters.readHash(seqRef); 56 String mgfHash = OAEPParameters.readMgfHash(seqRef); 57 if (NativeCrypto.asn1_read_next_tag_is(seqRef, 2)) { 58 long saltRef = 0; 59 try { 60 saltRef = NativeCrypto.asn1_read_tagged(seqRef); 61 saltLength = (int) NativeCrypto.asn1_read_uint64(saltRef); 62 } finally { 63 NativeCrypto.asn1_read_free(saltRef); 64 } 65 } 66 if (NativeCrypto.asn1_read_next_tag_is(seqRef, 3)) { 67 long trailerField; 68 long trailerRef = 0; 69 try { 70 trailerRef = NativeCrypto.asn1_read_tagged(seqRef); 71 trailerField = (int) NativeCrypto.asn1_read_uint64(trailerRef); 72 } finally { 73 NativeCrypto.asn1_read_free(trailerRef); 74 } 75 // 1 is the only legal value for trailerField 76 if (trailerField != 1) { 77 throw new IOException("Error reading ASN.1 encoding"); 78 } 79 } 80 81 if (!NativeCrypto.asn1_read_is_empty(seqRef) 82 || !NativeCrypto.asn1_read_is_empty(readRef)) { 83 throw new IOException("Error reading ASN.1 encoding"); 84 } 85 this.spec = new PSSParameterSpec(hash, "MGF1", new MGF1ParameterSpec(mgfHash), 86 saltLength, 1); 87 } finally { 88 NativeCrypto.asn1_read_free(seqRef); 89 NativeCrypto.asn1_read_free(readRef); 90 } 91 } 92 93 @Override engineInit(byte[] bytes, String format)94 protected void engineInit(byte[] bytes, String format) throws IOException { 95 if ((format == null) || format.equals("ASN.1") || format.equals("X.509")) { 96 engineInit(bytes); 97 } else { 98 throw new IOException("Unsupported format: " + format); 99 } 100 } 101 102 @Override 103 @SuppressWarnings("unchecked") engineGetParameterSpec(Class<T> aClass)104 protected <T extends AlgorithmParameterSpec> T engineGetParameterSpec(Class<T> aClass) 105 throws InvalidParameterSpecException { 106 if ((aClass != null) && aClass == PSSParameterSpec.class) { 107 return (T) spec; 108 } else { 109 throw new InvalidParameterSpecException("Unsupported class: " + aClass); 110 } 111 } 112 113 @Override engineGetEncoded()114 protected byte[] engineGetEncoded() throws IOException { 115 long cbbRef = 0; 116 long seqRef = 0; 117 try { 118 cbbRef = NativeCrypto.asn1_write_init(); 119 seqRef = NativeCrypto.asn1_write_sequence(cbbRef); 120 OAEPParameters.writeHashAndMgfHash(seqRef, spec.getDigestAlgorithm(), 121 (MGF1ParameterSpec) spec.getMGFParameters()); 122 // Implementations are prohibited from writing the default value for any of the fields 123 if (spec.getSaltLength() != 20) { 124 long tagRef = 0; 125 try { 126 tagRef = NativeCrypto.asn1_write_tag(seqRef, 2); 127 NativeCrypto.asn1_write_uint64(tagRef, spec.getSaltLength()); 128 } finally { 129 NativeCrypto.asn1_write_flush(seqRef); 130 NativeCrypto.asn1_write_free(tagRef); 131 } 132 } 133 // 1 is the only legal value for trailerField and the default, so ignore it 134 return NativeCrypto.asn1_write_finish(cbbRef); 135 } catch (IOException e) { 136 NativeCrypto.asn1_write_cleanup(cbbRef); 137 throw e; 138 } finally { 139 NativeCrypto.asn1_write_free(seqRef); 140 NativeCrypto.asn1_write_free(cbbRef); 141 } 142 } 143 144 @Override engineGetEncoded(String format)145 protected byte[] engineGetEncoded(String format) throws IOException { 146 if ((format == null) || format.equals("ASN.1") || format.equals("X.509")) { 147 return engineGetEncoded(); 148 } 149 throw new IOException("Unsupported format: " + format); 150 } 151 152 @Override engineToString()153 protected String engineToString() { 154 return "Conscrypt PSS AlgorithmParameters"; 155 } 156 } 157