1 2 #include <petscwebclient.h> 3 4 static BIO *bio_err = NULL; 5 6 #define PASSWORD "password" 7 8 #if defined(PETSC_USE_CERTIFICATE) 9 static int password_cb(char *buf,int num, int rwflag,void *userdata) 10 { 11 if (num < strlen(PASSWORD)+1) return(0); 12 strcpy(buf,PASSWORD); 13 return(strlen(PASSWORD)); 14 } 15 #endif 16 17 static void sigpipe_handle(int x) 18 { 19 } 20 21 #undef __FUNCT__ 22 #define __FUNCT__ "PetscSSLInitializeContext" 23 /* 24 PetscSSLInitializeContext - Set up an SSL context suitable for initiating HTTPS requests. 25 26 If built with PETSC_USE_CERTIFICATE requires the user have created a self-signed certificate with 27 28 $ ./CA.pl -newcert (using the passphrase of password) 29 $ cat newkey.pem newcert.pem > sslclient.pem 30 31 and put the resulting file in either the current directory (with the application) or in the home directory. This seems kind of 32 silly but it was all I could figure out. 33 34 */ 35 PetscErrorCode PetscSSLInitializeContext(SSL_CTX **octx) 36 { 37 SSL_METHOD *meth; 38 SSL_CTX *ctx; 39 #if defined(PETSC_USE_CERTIFICATE) 40 char keyfile[PETSC_MAX_PATH_LEN]; 41 PetscBool exists; 42 PetscErrorCode ierr; 43 #endif 44 45 PetscFunctionBegin; 46 if (!bio_err){ 47 SSL_library_init(); 48 SSL_load_error_strings(); 49 bio_err = BIO_new_fp(stderr,BIO_NOCLOSE); 50 } 51 52 /* Set up a SIGPIPE handler */ 53 signal(SIGPIPE,sigpipe_handle); 54 55 meth = SSLv23_method(); 56 ctx = SSL_CTX_new(meth); 57 58 #if defined(PETSC_USE_CERTIFICATE) 59 /* Locate keyfile */ 60 ierr = PetscStrcpy(keyfile,"sslclient.pem");CHKERRQ(ierr); 61 ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr); 62 if (!exists) { 63 ierr = PetscGetHomeDirectory(keyfile,PETSC_MAX_PATH_LEN);CHKERRQ(ierr); 64 ierr = PetscStrcat(keyfile,"/");CHKERRQ(ierr); 65 ierr = PetscStrcat(keyfile,"sslclient.pem");CHKERRQ(ierr); 66 ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr); 67 if (!exists) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate sslclient.pem file in current directory or home directory"); 68 } 69 70 /* Load our keys and certificates*/ 71 if (!(SSL_CTX_use_certificate_chain_file(ctx,keyfile))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read certificate file"); 72 73 SSL_CTX_set_default_passwd_cb(ctx,password_cb); 74 if (!(SSL_CTX_use_PrivateKey_file(ctx,keyfile,SSL_FILETYPE_PEM))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read key file"); 75 #endif 76 77 *octx = ctx; 78 PetscFunctionReturn(0); 79 } 80 81 #undef __FUNCT__ 82 #define __FUNCT__ "PetscSSLDestroyContext" 83 PetscErrorCode PetscSSLDestroyContext(SSL_CTX *ctx) 84 { 85 PetscFunctionBegin; 86 SSL_CTX_free(ctx); 87 PetscFunctionReturn(0); 88 } 89 90 #undef __FUNCT__ 91 #define __FUNCT__ "PetscHTTPSRequest" 92 /* 93 PetscHTTPSRequest - Send a request to an HTTPS server 94 95 Input Parameters: 96 + type - either "POST" or "GET" 97 . url - complete URL of request including https:// 98 . header - additional header information, may be NULL 99 . ctype - data type of body, for example application/json 100 . body - data to send to server 101 . ssl - obtained with PetscHTTPSConnect() 102 - buffsize - size of buffer 103 104 Output Parameter: 105 . buff - everything returned from server 106 */ 107 PetscErrorCode PetscHTTPSRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],SSL *ssl,char buff[],size_t buffsize) 108 { 109 char *request=0; 110 char contentlength[40],contenttype[80]; 111 int r; 112 size_t request_len,len,headlen,bodylen,contentlen,urllen,typelen,contenttypelen = 0; 113 PetscErrorCode ierr; 114 PetscBool flg; 115 116 PetscFunctionBegin; 117 ierr = PetscStrbeginswith(url,"https://",&flg);CHKERRQ(ierr); 118 if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"URL must begin with https://"); 119 if (header) { 120 ierr = PetscStrendswith(header,"\r\n",&flg);CHKERRQ(ierr); 121 if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"header must end with \\r\\n"); 122 } 123 124 ierr = PetscStrlen(type,&typelen);CHKERRQ(ierr); 125 ierr = PetscStrlen(url,&urllen);CHKERRQ(ierr); 126 if (ctype) { 127 ierr = PetscSNPrintf(contenttype,80,"Content-Type: %s\r\n",ctype);CHKERRQ(ierr); 128 ierr = PetscStrlen(contenttype,&contenttypelen);CHKERRQ(ierr); 129 } 130 ierr = PetscStrlen(header,&headlen);CHKERRQ(ierr); 131 ierr = PetscStrlen(body,&bodylen);CHKERRQ(ierr); 132 ierr = PetscSNPrintf(contentlength,40,"Content-Length: %d\r\n\r\n",(int)bodylen);CHKERRQ(ierr); 133 ierr = PetscStrlen(contentlength,&contentlen);CHKERRQ(ierr); 134 135 /* Now construct our HTTP request */ 136 request_len = typelen + 1 + urllen + 35 + headlen + contenttypelen + contentlen + bodylen + 1; 137 ierr = PetscMalloc1(request_len,&request);CHKERRQ(ierr); 138 ierr = PetscStrcpy(request,type);CHKERRQ(ierr); 139 ierr = PetscStrcat(request," ");CHKERRQ(ierr); 140 ierr = PetscStrcat(request,url);CHKERRQ(ierr); 141 ierr = PetscStrcat(request," HTTP/1.1\r\nUser-Agent:PETScClient\r\n");CHKERRQ(ierr); 142 ierr = PetscStrcat(request,header);CHKERRQ(ierr); 143 if (ctype) { 144 ierr = PetscStrcat(request,contenttype);CHKERRQ(ierr); 145 } 146 ierr = PetscStrcat(request,contentlength);CHKERRQ(ierr); 147 ierr = PetscStrcat(request,body);CHKERRQ(ierr); 148 ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr); 149 ierr = PetscInfo1(NULL,"HTTPS request follows: \n%s\n",request);CHKERRQ(ierr); 150 151 r = SSL_write(ssl,request,request_len); 152 switch (SSL_get_error(ssl,r)){ 153 case SSL_ERROR_NONE: 154 if (request_len != r) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Incomplete write to SSL socket"); 155 break; 156 default: 157 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL socket write problem"); 158 } 159 160 /* Now read the server's response, assuming that it's terminated by a close */ 161 r = SSL_read(ssl,buff,(int)buffsize); 162 len = r; 163 switch (SSL_get_error(ssl,r)){ 164 case SSL_ERROR_NONE: 165 break; 166 case SSL_ERROR_ZERO_RETURN: 167 SSL_shutdown(ssl); /* ignore shutdown error message */ 168 break; 169 case SSL_ERROR_SYSCALL: 170 break; 171 default: 172 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL read problem"); 173 } 174 buff[len] = 0; /* null terminate string */ 175 ierr = PetscInfo1(NULL,"HTTPS result follows: \n%s\n",buff);CHKERRQ(ierr); 176 177 SSL_free(ssl); 178 ierr = PetscFree(request);CHKERRQ(ierr); 179 PetscFunctionReturn(0); 180 } 181 182 #undef __FUNCT__ 183 #define __FUNCT__ "PetscHTTPSConnect" 184 PetscErrorCode PetscHTTPSConnect(const char host[],int port,SSL_CTX *ctx,int *sock,SSL **ssl) 185 { 186 BIO *sbio; 187 PetscErrorCode ierr; 188 189 PetscFunctionBegin; 190 /* Connect the TCP socket*/ 191 ierr = PetscOpenSocket(host,port,sock);CHKERRQ(ierr); 192 193 /* Connect the SSL socket */ 194 *ssl = SSL_new(ctx); 195 sbio = BIO_new_socket(*sock,BIO_NOCLOSE); 196 SSL_set_bio(*ssl,sbio,sbio); 197 if (SSL_connect(*ssl) <= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL connect error"); 198 PetscFunctionReturn(0); 199 } 200 201