@@ -293,6 +293,90 @@ where
293293 }
294294}
295295
296+ #[ cfg( feature = "pem" ) ]
297+ #[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
298+ pub enum PemParseError {
299+ ///Indicates invalid PEM string
300+ Pem ( pem:: Error ) ,
301+ ///Indicates invalid pkcs8 EC key
302+ Pkcs8 ( :: pkcs8:: Error ) ,
303+ ///Indicates invalid Sec1 EC key
304+ Sec1 ( :: sec1:: Error ) ,
305+ ///Unable to recognize document label
306+ UnknownLabel ,
307+ }
308+
309+ #[ cfg( feature = "pem" ) ]
310+ impl From < pem:: Error > for PemParseError {
311+ #[ inline( always) ]
312+ fn from ( error : pem:: Error ) -> Self {
313+ Self :: Pem ( error)
314+ }
315+ }
316+
317+ #[ cfg( feature = "pem" ) ]
318+ impl From < :: pkcs8:: Error > for PemParseError {
319+ #[ inline( always) ]
320+ fn from ( error : :: pkcs8:: Error ) -> Self {
321+ Self :: Pkcs8 ( error)
322+ }
323+ }
324+
325+ #[ cfg( feature = "pem" ) ]
326+ impl From < :: sec1:: Error > for PemParseError {
327+ #[ inline( always) ]
328+ fn from ( error : :: sec1:: Error ) -> Self {
329+ Self :: Sec1 ( error)
330+ }
331+ }
332+
333+ #[ cfg( feature = "pem" ) ]
334+ impl fmt:: Display for PemParseError {
335+ fn fmt ( & self , fmt : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
336+ match self {
337+ Self :: Pem ( error) => fmt. write_fmt ( format_args ! ( "Failed to parse PEM: {error}" ) ) ,
338+ Self :: UnknownLabel => fmt. write_str ( "Unrecognized key label" ) ,
339+ Self :: Pkcs8 ( error) => fmt. write_fmt ( format_args ! ( "Faoled to parse Pkcs8 key: {error}" ) ) ,
340+ Self :: Sec1 ( error) => fmt. write_fmt ( format_args ! ( "Faoled to parse SEC1 key: {error}" ) ) ,
341+ }
342+ }
343+ }
344+
345+ #[ cfg( feature = "std" ) ]
346+ impl core:: error:: Error for PemParseError { }
347+
348+ #[ cfg( feature = "pem" ) ]
349+ impl < C > SecretKey < C >
350+ where
351+ C : AssociatedOid + Curve + ValidatePublicKey ,
352+ FieldBytesSize < C > : ModulusSize ,
353+ {
354+ /// Parse [`SecretKey`] from PEM-encoded private key.
355+ ///
356+ /// Supported formats:
357+ /// - `SEC1` - requires feature `sec1`
358+ /// - `PKCS #8` - requires feature `pkcs8`
359+ ///
360+ /// # Errors
361+ /// - If `pem` is not valid PEM encoded private key
362+ /// - If label within `pem` is not known valid label
363+ /// - If label is valid, but unable to decode DER content of the PEM file
364+ #[ cfg( feature = "pem" ) ]
365+ pub fn from_pem ( pem : & str ) -> :: core:: result:: Result < Self , PemParseError > {
366+ let ( label, der_bytes) = pem:: decode_vec ( pem. as_bytes ( ) ) . map_err ( PemParseError :: Pem ) ?;
367+
368+ if label == sec1:: EcPrivateKey :: PEM_LABEL {
369+ return :: sec1:: DecodeEcPrivateKey :: from_sec1_der ( & der_bytes)
370+ . map_err ( PemParseError :: Sec1 ) ;
371+ } else if :: pkcs8:: PrivateKeyInfoRef :: validate_pem_label ( label) . is_ok ( ) {
372+ return :: pkcs8:: DecodePrivateKey :: from_pkcs8_der ( & der_bytes)
373+ . map_err ( PemParseError :: Pkcs8 ) ;
374+ }
375+
376+ Err ( PemParseError :: UnknownLabel )
377+ }
378+ }
379+
296380impl < C > ConstantTimeEq for SecretKey < C >
297381where
298382 C : Curve ,
0 commit comments