Configuration-as-code-plugin: PKCS12 cert doesn't work anymore

Created on 4 Jun 2019  路  22Comments  路  Source: jenkinsci/configuration-as-code-plugin

Your checklist for this issue

馃毃 Please review the guidelines for contributing to this repository.

  • [x] Jenkins version: 2.164.3

  • [x] Plugin version: 1.19

  • [x] OS: Docker Image jenkins/jenkins:lts

Description

We have a PKCS12 certificate being added using Jenkins Casc:

- certificate:
    scope: GLOBAL
    id: "NexusIQ"
    description: "NexusIQ"
    password: "{{ .Values.jenkinsConfig.secrets.nexusIQCertPassword }}"
    keyStoreSource:
      uploaded:
        uploadedKeystore: "/run/secrets/nexusiq-certs/nexusiq.pkcs"

This was working fine before using fileOnMaster and keyStoreFile instead of uploaded and uploadedKeystore.

Now we get this error:

Could not load keystorejava.io.IOException: DerInputStream.getLength(): lengthTag=59, too big.  at sun.security.util.DerInputStream.getLength(DerInputStream.java:599)  at sun.security.util.DerValue.init(DerValue.java:391)   at sun.security.util.DerValue.<init>(DerValue.java:332) at sun.security.util.DerValue.<init>(DerValue.java:345) at sun.security.pkcs12.PKCS12KeyStore.engineLoad(PKCS12KeyStore.java:1938)  at java.security.KeyStore.load(KeyStore.java:1445)  at com.cloudbees.plugins.credentials.impl.CertificateCredentialsImpl$KeyStoreSourceDescriptor.validateCertificateKeystore(CertificateCredentialsImpl.java:306)  at com.cloudbees.plugins.credentials.impl.CertificateCredentialsImpl$UploadedKeyStoreSource$DescriptorImpl.doCheckUploadedKeystore(CertificateCredentialsImpl.java:599) at java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:627) at org.kohsuke.stapler.Function$MethodFunction.invoke(Function.java:396)    at org.kohsuke.stapler.Function$InstanceFunction.invoke(Function.java:408)  at org.kohsuke.stapler.Function.bindAndInvoke(Function.java:212)    at org.kohsuke.stapler.Function.bindAndInvokeAndServeResponse(Function.java:145)    at org.kohsuke.stapler.MetaClass$11.doDispatch(MetaClass.java:537)  at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:58)    at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:739)  at org.kohsuke.stapler.Stapler.invoke(Stapler.java:870) at org.kohsuke.stapler.MetaClass$4.doDispatch(MetaClass.java:282)   at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:58)    at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:739)  at org.kohsuke.stapler.Stapler.invoke(Stapler.java:870) at org.kohsuke.stapler.Stapler.invoke(Stapler.java:668) at org.kohsuke.stapler.Stapler.service(Stapler.java:238)    at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:865)   at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1655)  at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:154) at org.jenkinsci.plugins.ssegateway.Endpoint$SSEListenChannelFilter.doFilter(Endpoint.java:243) at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:151) at io.jenkins.blueocean.auth.jwt.impl.JwtAuthenticationFilter.doFilter(JwtAuthenticationFilter.java:61) at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:151) at io.jenkins.blueocean.ResourceCacheControl.doFilter(ResourceCacheControl.java:134)    at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:151) at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:239) at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:215) at net.bull.javamelody.PluginMonitoringFilter.doFilter(PluginMonitoringFilter.java:88)  at org.jvnet.hudson.plugins.monitoring.HudsonMonitoringFilter.doFilter(HudsonMonitoringFilter.java:114) at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:151) at jenkins.telemetry.impl.UserLanguages$AcceptLanguageFilter.doFilter(UserLanguages.java:128)   at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:151) at hudson.util.PluginServletFilter.doFilter(PluginServletFilter.java:157)   at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)  at hudson.security.csrf.CrumbFilter.doFilter(CrumbFilter.java:99)   at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)  at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:84)    at hudson.security.UnwrapSecurityExceptionFilter.doFilter(UnwrapSecurityExceptionFilter.java:51)    at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)    at jenkins.security.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:117)    at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)    at org.acegisecurity.providers.anonymous.AnonymousProcessingFilter.doFilter(AnonymousProcessingFilter.java:125) at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)    at org.acegisecurity.ui.rememberme.RememberMeProcessingFilter.doFilter(RememberMeProcessingFilter.java:142) at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)    at org.acegisecurity.ui.AbstractProcessingFilter.doFilter(AbstractProcessingFilter.java:271)    at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)    at jenkins.security.BasicHeaderProcessor.doFilter(BasicHeaderProcessor.java:93) at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)    at org.acegisecurity.context.HttpSessionContextIntegrationFilter.doFilter(HttpSessionContextIntegrationFilter.java:249) at hudson.security.HttpSessionContextIntegrationFilter2.doFilter(HttpSessionContextIntegrationFilter2.java:67)  at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)    at hudson.security.ChainedServletFilter.doFilter(ChainedServletFilter.java:90)  at hudson.security.HudsonFilter.doFilter(HudsonFilter.java:171) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)  at org.kohsuke.stapler.compression.CompressionFilter.doFilter(CompressionFilter.java:49)    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)  at hudson.util.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:82)    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)  at org.kohsuke.stapler.DiagnosticThreadNameFilter.doFilter(DiagnosticThreadNameFilter.java:30)  at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)  at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:533)   at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:146)    at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:524)  at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)  at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:257)    at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1595)   at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:255)    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1340)   at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:203) at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:473)    at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1564)    at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:201) at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1242)    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:144)    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)  at org.eclipse.jetty.server.Server.handle(Server.java:503)  at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:364)    at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:260)  at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:305)  at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)    at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:118) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:333)   at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:310) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:168)    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:126)   at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:366) at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:765) at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:683)  at java.lang.Thread.run(Thread.java:748)

Adding it by hand works fine...

bug plugin-compatibility

Most helpful comment

FYI JCasC is getting native support for variable expansion with base64 and file read. See #1408

All 22 comments

This an issue with the credential plugin not JCasC :sweat:

But how it works fine if we do the same thing by hand?

Because JCasC expects you to convert the file to bytes.

uploadedKeystore: {{ .Values.jenkinsConfig.secrets.nexusIQCertBytes }}

image
This was working fine before we updated the plugin...

Are you saying the upload (which seems to work in a different way than going directly to the file on master) will not work for this?

uploadedKeystore is not the same as keyStoreFile.

uploadedKeystore expects the file to be uploaded via Stapler UI which JCasC has no notion of.

Stapler request converts the uploaded file into bytes. You can do the same.
Again this is most likely a bug in credential plugin, that they did not consider JCasC.

Hey @casz, thanks a lot for your help, for now this worked:
--set jenkinsConfig.secrets.nexusIQCert="$(cat nexusiq.pkcs|base64)"
and:
uploadedKeystore: "{{ .Values.jenkinsConfig.secrets.nexusIQCert }}"

Thanks for the tip @meyerbro I'll see if we can improve the experience and be allowed to point to a file :sweat:

FYI JCasC is getting native support for variable expansion with base64 and file read. See #1408

Hi, for some reason using
uploadedKeystore: "$(cat /path/to/key.p12)" doesn't work using jcasc. But i am able use the same key.p12 if i upload manually. It need not be base64 encoded. Any idea why this doesn't work for me?

because the credential plugin excepts it to be base64 encoded.

because the credential plugin excepts it to be base64 encoded.

Thanks for the quick reply,
But i use same cert manually uploading it,.without any base64 encoding,.it configures correctly then.
While checking the credential ui which is created using casc,.i get the following error in pkcs12 field,..

I also just tried uploadedKeystore: "$(cat /path/to/key.p12|base64)",.which also gives me same error.

Could not load keystore java.io.IOException: DerInputStream.getLength(): lengthTag=43, too big. at sun.security.util.DerInputStream.getLength(DerInputStream.java:599) at

When you manually upload the plugin ensure base64 encoding.

You need to base64 the binary content. Not the text content

When you manually upload the plugin ensure base64 encoding.

You need to base64 the binary content. Not the text content

Yup thanks for the info,..but i also tried

uploadedKeystore: "$(cat /path/to/key.p12|base64)"

and key.p12 is binary content. I am not sure what I might be doing wrong here.

@jetersen ,I have actually got the yaml wrong i guess. What happened is
uploadedKeystore: "$(cat /path/to/key.p12|base64)"
takes ""$(cat /path/to/key.p12|base64)" this as string ,.and does not perform the cat and substitute it with the key file. I am so sorry for this misunderstanding.
Can you show me a sample of using cat within the casc.yaml the right way?

atm you cannot do this with JCasC, you have to import the secret some other way.

If using docker you could do the cat,base64 into a environment variable.
Same is possible with Kubernetes secrets.

Or wait for #1408 which adds support :)

atm you cannot do this with JCasC, you have to import the secret some other way.

If using docker you could do the cat,base64 into a environment variable.
Same is possible with Kubernetes secrets.

Or wait for #1408 which adds support :)

I am using Jenkins operator, and using Kubernetes secrets for most of credentials except this,.since it's a file I am generating dynamically. So if i am to use kubernetes secrets, then should I save a secret key like,
SECRET = "$(cat /path/to/key.p12|base64)" and refer it in casc.yaml as
uploadedKeystore: ${SECRET}

And #1408,.i just saw that it's more better way for this case,.and see that u have completed it and merging right now. Please let me know once it's complete and released for use.

@jetersen ,.can i please get the .hpi for casc with #1408 . I could'nt find any artifacts yet.

Was this page helpful?
0 / 5 - 0 ratings